#!/usr/bin/perl

use XML::LibXML;
require LWP::UserAgent;
use HTTP::Request::Common;
use Archive::Zip qw (:ERROR_CODES :CONSTANTS );
use Digest::MD5 qw(md5 md5_hex md5_base64);
use File::stat;
use PlistMaker qw ( :all );
use Text::Unaccent;

use vars qw(@ISA);

# TODO: Figure out what plist file is causing the problems. DONE
#       Divide and conquer. ?!?!
#       Separate installer title from directory title. DONE
#       Copy the GutenMark plist across you idiot! DONE
#       Upload the GutenMark .zip to both locations! DONE
#       Make the code language sensitive DONE
#       Change the invocation of GutenSplit DONE

my $debug      = 0;
my $debug_copy = 0;

%::http_passwords = ();
my $current_realm;

{
    package RequestAgent;
    @ISA = qw(LWP::UserAgent);

    sub new
    { 
	my $self = LWP::UserAgent::new(@_);
	$self->agent("Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12");
	$self->timeout(30);
	$self->env_proxy;
	$self->cookie_jar({ file =>"$ENV{HOME}/.cookies.txt", autosave => 1 });
	
	$self;
    }
}

my $gutenberg_repo = "gutenberg_scifi";
my $gutenberg_rdfs = "$gutenberg_repo/rdfs";

# 
# Get the etext number
# Find the appropriate etext
# Get the Author
# Get the Title
# Figure out the type of release (html/txt)?
# Find the zip
# Download the zip

# parse the rdf document
my $parser = XML::LibXML->new ();
$parser->keep_blanks (0);

my $book_id = @ARGV[0]; 
my $doc = $parser->parse_file ("$gutenberg_rdfs/$book_id.rdf");

my %books;

# parse XML into %books data structure
#
# parse book nodes
my @booknodes = $doc->findnodes ('/rdf:RDF/pgterms:etext');
#
foreach my $booknode (@booknodes) {
    # this is a book description node
    my $etext_no = $booknode->getAttribute ('rdf:ID');
    $etext_no =~ s/^etext//;
    my $o = {};

    foreach my $title ($booknode->findnodes ('dc:title//text()')) {
        push @{$o->{'titles'}}, $title->textContent;
    }
    foreach my $creator ($booknode->findnodes ('dc:creator//text()')) {
        push @{$o->{'authors'}}, $creator->textContent;
    }


    foreach my $language ($booknode->findnodes('dc:language/dcterms:ISO639-2/rdf:value//text()')) {
        $o->{'language'} = $language->textContent;
    }

    $books{$etext_no} = $o;
    print "$etext_no: ",$o->{'titles'}[0],"\n" unless $debug == 0;
}

@booknodes = undef; # release some memory

print "Getting file types\n";
# parse file nodes
# Find the zip nodes first (if we can)
my @filenodes = $doc->findnodes ('/rdf:RDF/pgterms:file');
print "Iterating file nodes\n" unless $debug == 0;
foreach my $filenode (@filenodes) {
    my $seen_zip  = 0;
    my $format = "";

    my $etext_no = "";
    foreach my $n ($filenode->findnodes ('dcterms:isFormatOf')) {
        # this is a file description node
        $etext_no = $n->getAttribute ('rdf:resource');
        $etext_no =~ s/^\#etext//;
    }

    print "Found book number: ***$etext_no***\n" unless $debug == 0;
    my $url = $filenode->getAttribute ('rdf:about');
    print "Checking filename : $url\n" unless $debug == 0;

    foreach my $n ($filenode->findnodes('dc:format/dcterms:IMT/rdf:value//text()')) {
	# See if we've got an html zip.
	if ($n->textContent() eq "application/zip") {
	    print "Found zip archive...\n" unless $debug == 0;
	    $seen_zip = 1;
	}
	
	if ($n->textContent =~ /(text\/plain|text\/html)/) {
	    $format = $1;
	}
	print "FORMAT: $format\n" unless $debug == 0;
    }

    if ($seen_zip == 1 && ($format eq "text/html" || $format eq "text/plain")) {
	print "Stashing, $etext_no/***$format*** -> $url\n" unless $debug == 0; 
	$books{$etext_no}->{$format} = $url;
    }

}

print "  Text Details: ", $books{$book_id}->{"text/plain"}, "\n";
print "  HTML Details: ", $books{$book_id}->{"text/html"}, "\n";

print "Done parsing file nodes\n";
@filenodes = undef; # release some memory

# Now we populate the plist file for the book.

my $BookTitle = $books{$book_id}->{'titles'}[0] ;
# Remove the spaces in the book title, otherwise the gutenmark won't work.
my $BookDir = $BookTitle;
$BookDir =~ s/[[:space:]]/_/g;
$BookDir =~ s/[[:punct:]]/_/g;
$BookDir = unac_string("UTF-8", $BookDir);
$BookTitle = unac_string("UTF-8", $BookTitle);
$BookLang = $books{$book_id}->{'language'};

if ($BookLang ne "en" && $BookLang ne "fr" && $BookLang ne "es" && $BookLang ne "it" && $BookLang ne "de") {
    print "\tUnknown Language - $BookLang, defaulting to English\n";
    $BookLang = "en";
}

my $BookNumber = $book_id;
my $BookAuthor = join ', ', @{$books{$book_id}->{'authors'}};

my $gutenberg_preflight = 
    p_ifnot(IsPackageInstalled("com.natetrue.iphone.iphone_binkit"),
	    AbortOperation("You must install the \"BSD Subsystem\" package from Installer first!  It's in the System Category.")) .
    p_ifnot(IsPackageInstalled("ca.pollock.GutenMark"),
            AbortOperation("You must install the \"GutenMark\" package first!  It's in the Utilities Category."));

my $gutenberg_html_install =
    p_if(IsFirmwareVersion("1.1.3", "1.1.4"),
         SetStatus("Changing Permissions").
         Exec("/bin/chmod -R 755 /var/mobile/Media/EBooks").
         Exec("/usr/bin/chown -R mobile /var/mobile/Media/EBooks/.").
         SetStatus("Running GutenSplit").
         Exec("/usr/bin/GutenSplit -1 -2 -3 -4 --no-toc --no-skip /var/mobile/Media/EBooks/$BookDir/${BookNumber}-h.htm /var/mobile/Media/EBooks/$BookDir/Chapter_")
    ).
    p_if(IsFirmwareVersion("1.0.0", "1.0.1", "1.0.2", "1.1.1", "1.1.2" ),
         SetStatus("Changing Permissions").
         Exec("/bin/chmod -R 755 /var/root/Media/EBooks") .
         SetStatus("Running GutenSplit").
         Exec("/usr/bin/GutenSplit -1 -2 -3 -4 --no-toc --no-skip /var/root/Media/EBooks/$BookDir/${BookNumber}-h.htm /var/root/Media/EBooks/$BookDir/Chapter_")
    );


my $gutenberg_txt_install = 
    p_if(IsFirmwareVersion("1.1.3", "1.1.4"),
         SetStatus("Changing Permissions").
         Exec("/bin/chmod -R 755 /var/mobile/Media/EBooks").
         Exec("/usr/bin/chown -R mobile /var/mobile/Media/EBooks/.").
         SetStatus("Running GutenMark").
         Exec("/usr/bin/GutenMark --profile=$BookLang --no-toc --config=/etc/GutenMark.cfg /var/mobile/Media/EBooks/$BookDir/$BookNumber.txt /var/mobile/Media/EBooks/$BookDir/${BookNumber}-h.htm") .
         SetStatus("Running GutenSplit").
         Exec("/usr/bin/GutenSplit --no-toc /var/mobile/Media/EBooks/$BookDir/${BookNumber}-h.htm /var/mobile/Media/EBooks/$BookDir/Chapter_")
    ).
    p_if(IsFirmwareVersion("1.0.0", "1.0.1", "1.0.2", "1.1.1", "1.1.2" ),
         SetStatus("Changing Permissions").
         Exec("/bin/chmod -R 755 /var/root/Media/EBooks") . 
         SetStatus("Running GutenMark").
         Exec("/usr/bin/GutenMark --profile=$BookLang --no-toc --config=/etc/GutenMark.cfg /var/root/Media/EBooks/$BookDir/$BookNumber.txt /var/root/Media/EBooks/$BookDir/${BookNumber}-h.htm") .
         SetStatus("Running GutenSplit").
         Exec("/usr/bin/GutenSplit --no-toc /var/root/Media/EBooks/$BookDir/${BookNumber}-h.htm /var/root/Media/EBooks/$BookDir/Chapter_")
    );

my $gutenberg_uninstall = 
    RemovePath("~/Media/EBooks/$BookDir");

# Now decide if we're using a zip html or zip txt file.
my $BookURL = $books{$BookNumber}->{"text/html"};
my $Book_install = $gutenberg_html_install;
my $BookFormat = "HTML";
if (! defined $BookURL) {
    $Book_install = $gutenberg_txt_install;
    $BookURL = $books{$BookNumber}->{"text/plain"};
    $BookFormat = "Text";
    print "Falling back to .txt file\n";

}

if (! defined $BookURL) {
    die("Format unknown!");
}

my $Book_preflight = $gutenberg_preflight;
my $Book_uninstall = $gutenberg_uninstall;

# Retrieve the .zip file, get the size and the hash.
my $ua = RequestAgent->new;

# Get the .zip file
my $book_zip = "$gutenberg_repo/zips/$BookNumber.zip";
if ( ! -f $book_zip ) {
    print "Retrieving book zip file: $BookURL -> $book_zip\n";
    my $mirror_result = $ua->mirror($BookURL, $book_zip);
}

print "Found the .zip: $book_zip\n";

print "Book Details:\n";
print "\tTitle\t$BookTitle\n";
print "\tDir\t$BookDir\n";
print "\tAuthor\t$BookAuthor\n";
print "\tNumber\t$BookNumber\n";
print "\tURL\t$BookURL\n";
print "\tFormat\t$BookFormat\n";
print "\tLanguage\t$BookLang\n";

# Size and md5
open(FILE, $book_zip) or die $book_url . "Can't open '$file' for hash: $!";
binmode(FILE);
my $BookMD5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
close(FILE);
print "\thash\t$BookMD5\n" unless $debug == 0;
my $sb = stat($book_zip);
my $BookSize = $sb->size;
print "\tsize\t$BookSize\n" unless $debug == 0;

# Now the install/uninstall instructions.
my $zipFile = Archive::Zip->new();
die $book_zip . "read error" unless ($zipFile->read($book_zip) == AZ_OK);
my @files = $zipFile->memberNames();
print "\tfileCount\t".scalar(@files)."\n" unless $debug == 0;

$copy_files = "";
# Alt text in the html is the book title?
# illus01.png || image001.jpg || ill001.png
# First we take an extra copy of the cover image.
#$copy_files .="           <array>
#             <string>CopyPath</string>
#             <string>$SKU.jpg</string>
#             <string>~/Media/EBooks/$title/cover.jpg</string>
#           </array>\n";

# There are a couple of different formats:
# $BookID/file -> $file
# *.txt -> $BookID.txt
# *.htm -> $BookID-h.htm
# $BookID-h/file -> $file
my $copy_files;
foreach my $file (@files) {
    my $destfile = $file;
    $destfile =~ s/^$BookNumber\///;
    $destfile =~ s/${BookNumber}-h\///;
    if ($destfile =~ /\.txt$/) {
	$destfile = "${BookNumber}.txt";
    }

    if ($destfile =~ /\.htm$/) {
	$destfile = "${BookNumber}-h.htm";
    }

    print "$file => $destfile\n" unless $debug_copy == 0;
    $copy_files .= CopyPath("$file", "~/Media/EBooks/$BookDir/$destfile");
}

$Book_install = $copy_files . $Book_install;

# Finally the plist.
my %BookDescriptor = (
    bundleIdentifier => "ca.pollock.gutenberg.$BookNumber", 
    name => $BookTitle,
    version => "1.0",
    location => $BookURL,
    category => "Gutenberg SciFi (" .$BookLang . ")", 
    size => $BookSize,
    hash => $BookMD5,
    url => "http://jason-pollock.blogspot.com/",
    maintainer => "Jason Pollock",
    contact => 'jason@pollock.ca',
    description => "by $BookAuthor",
    install => $Book_install,
    preflight => $Book_preflight,
    postflight => "" ,
    uninstall => $Book_uninstall,
    update => ""
    );

my $BookPLIST = CreatePackage(%BookDescriptor);

my $plist_name = "$gutenberg_repo/plists/$BookNumber.plist";

open PLIST, ">$plist_name" or die "Unable to open $plist_name";
print PLIST $BookPLIST;
close PLIST;
